package com.stars.easyms.datasource.autoconfigure;

import com.alibaba.druid.support.http.StatViewServlet;
import com.stars.easyms.datasource.batch.BatchCommit;
import com.stars.easyms.datasource.EasyMsMultiDataSource;
import com.stars.easyms.datasource.annotation.EasyMsRepository;
import com.stars.easyms.datasource.EasyMsDataSourceFactory;
import com.stars.easyms.datasource.interceptor.*;
import com.stars.easyms.datasource.pointcut.FixedDataSourceMethodPointcutAdvisor;
import com.stars.easyms.datasource.pointcut.FixedDataSourceTypePointcutAdvisor;
import com.stars.easyms.datasource.pointcut.SpecifyDataSourceMethodPointcutAdvisor;
import com.stars.easyms.datasource.pointcut.SpecifyDataSourceTypePointcutAdvisor;
import com.stars.easyms.datasource.properties.EasyMsPropertiesHelper;
import com.stars.easyms.datasource.mybatis.*;
import com.stars.easyms.datasource.transaction.EasyMsDataSourceTransactionManager;
import com.stars.easyms.datasource.transaction.EasyMsTransactionInterceptor;
import org.apache.ibatis.plugin.Interceptor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.*;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;

import java.util.*;

/**
 * spring boot数据源及mybatis的配置类，非spring boot项目无需关注该配置类
 *
 * @author guoguifang
 * @date 2018-10-19 10:07
 * @since 1.0.0
 */
@Configuration
public class EasyMsDatasourceAutoConfiguration {

    @Bean
    public ServletRegistrationBean statViewServlet() {
        ServletRegistrationBean<StatViewServlet> statViewServlet = new ServletRegistrationBean<>();
        statViewServlet.setServlet(new StatViewServlet());
        statViewServlet.setName("DruidStatView");
        statViewServlet.addUrlMappings("/druid/*");
        return statViewServlet;
    }

    @Bean
    public EasyMsDataSourceFactory easyMsDataSourceFactory() {
        return new EasyMsDataSourceFactory();
    }

    @Bean
    public EasyMsMultiDataSource easyMsMultiDataSource(EasyMsDataSourceFactory easyMsDataSourceFactory) {
        return easyMsDataSourceFactory.createDataSource();
    }

    @Bean
    public EasyMsMybatisConfiguration easyMsMybatisConfiguration() {
        return new EasyMsMybatisConfiguration();
    }

    @Bean
    public EasyMsPageInterceptor easyMsPageInterceptor(EasyMsMultiDataSource dataSource, EasyMsMybatisConfiguration easyMsMybatisConfiguration) {
        EasyMsPageInterceptor easyMsPageInterceptor = new EasyMsPageInterceptor(easyMsMybatisConfiguration, dataSource);
        easyMsPageInterceptor.setProperties(EasyMsPropertiesHelper.getEasyMsPageHelperProperties().getProperties());
        return easyMsPageInterceptor;
    }

    @Bean
    public EasyMsSqlSessionFactory easyMsSqlSessionFactory(EasyMsMultiDataSource dataSource, EasyMsPageInterceptor easyMsPageInterceptor, EasyMsMybatisConfiguration easyMsMybatisConfiguration,
                                                           EasyMsQueryInterceptor easyMsQueryInterceptor, EasyMsUpdateInterceptor easyMsUpdateInterceptor) throws Exception {
        EasyMsSqlSessionFactoryBean sqlSessionFactoryBean = new EasyMsSqlSessionFactoryBean(easyMsMybatisConfiguration);
        // 指定数据源
        sqlSessionFactoryBean.setDataSource(dataSource);
        // 指定拦截器及分页插件
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.add(easyMsPageInterceptor);
        interceptors.add(easyMsUpdateInterceptor);
        interceptors.add(easyMsQueryInterceptor);
        sqlSessionFactoryBean.setPlugins(interceptors.toArray(new Interceptor[0]));
        // 指定基包
        sqlSessionFactoryBean.setTypeAliasesPackage(EasyMsPropertiesHelper.getEasyMsMybatisProperties().getTypeAliasesPackage());
        List<Resource> resourceList = new ArrayList<>();
        for (String mapperLocation : EasyMsPropertiesHelper.getEasyMsMybatisProperties().getMapperLocations()) {
            Resource[] resources = new PathMatchingResourcePatternResolver().getResources(mapperLocation);
            resourceList.addAll(Arrays.asList(resources));
        }
        // 指定xml文件位置
        sqlSessionFactoryBean.setMapperLocations(resourceList.toArray(new Resource[0]));
        return new EasyMsSqlSessionFactory(sqlSessionFactoryBean.getObject());
    }

    @Bean
    public EasyMsSqlSessionTemplate easyMsSqlSessionTemplate(EasyMsSqlSessionFactory easyMsSqlSessionFactory) {
        return new EasyMsSqlSessionTemplate(easyMsSqlSessionFactory);
    }

    @Bean
    @DependsOn({"easyMsMultiDataSource", "easyMsSqlSessionTemplate"})
    public EasyMsMapperScannerConfigurer easyMsMapperScannerConfigurer(ConfigurableApplicationContext applicationContext) {
        EasyMsMapperScannerConfigurer mapperScannerConfigurer = new EasyMsMapperScannerConfigurer(applicationContext);
        mapperScannerConfigurer.setSqlSessionTemplateBeanName("easyMsSqlSessionTemplate");
        mapperScannerConfigurer.setBasePackage(EasyMsPropertiesHelper.getEasyMsMybatisProperties().getTypeAliasesPackage());
        mapperScannerConfigurer.setAnnotationClass(EasyMsRepository.class);
        return mapperScannerConfigurer;
    }

    @Bean
    public FixedDataSourceTypePointcutAdvisor fixedDataSourceTypePointcutAdvisor() {
        return new FixedDataSourceTypePointcutAdvisor();
    }

    @Bean
    public FixedDataSourceMethodPointcutAdvisor fixedDataSourceMethodPointcutAdvisor() {
        return new FixedDataSourceMethodPointcutAdvisor();
    }

    @Bean
    public SpecifyDataSourceTypePointcutAdvisor specifyDataSourceTypePointcutAdvisor(EasyMsMultiDataSource dataSource) {
        return new SpecifyDataSourceTypePointcutAdvisor(dataSource);
    }

    @Bean
    public SpecifyDataSourceMethodPointcutAdvisor specifyDataSourceMethodPointcutAdvisor(EasyMsMultiDataSource dataSource) {
        return new SpecifyDataSourceMethodPointcutAdvisor(dataSource);
    }

    @Bean
    public EasyMsQueryInterceptor easyMsQueryInterceptor(EasyMsMultiDataSource dataSource) {
        return new EasyMsQueryInterceptor(dataSource);
    }

    @Bean
    public EasyMsUpdateInterceptor easyMsUpdateInterceptor(EasyMsMultiDataSource dataSource) {
        return new EasyMsUpdateInterceptor(dataSource);
    }

    @Bean
    public BatchCommit batchCommitDAO(EasyMsMultiDataSource dataSource, EasyMsSqlSessionFactory easyMsSqlSessionFactory) {
        return new BatchCommit(dataSource, easyMsSqlSessionFactory);
    }

    @Bean
    public EasyMsDataSourceTransactionManager easyMsDataSourceTransactionManager() {
        return new EasyMsDataSourceTransactionManager();
    }

    @Bean
    public EasyMsTransactionInterceptor easyMsTransactionInterceptor(EasyMsDataSourceTransactionManager easyMsDataSourceTransactionManager,
                                                                     ObjectProvider<BeanFactoryTransactionAttributeSourceAdvisor> advisorObjectProvider) {
        EasyMsTransactionInterceptor easyMsTransactionInterceptor = new EasyMsTransactionInterceptor(easyMsDataSourceTransactionManager);
        BeanFactoryTransactionAttributeSourceAdvisor advisor = advisorObjectProvider.getIfAvailable();
        if (advisor != null) {
            advisor.setAdvice(easyMsTransactionInterceptor);
        }
        return easyMsTransactionInterceptor;
    }
}